{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "basic_regression.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "FhGuhbZ6M5tl"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "AwOEIRJC6Une",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "KyPEtTqk6VdG",
        "colab": {}
      },
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "EIdT9iu_Z4Rb"
      },
      "source": [
        "# 회귀: 자동차 연비 예측하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bBIlTPscrIT9"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ko/r1/tutorials/keras/basic_regression.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />구글 코랩(Colab)에서 실행하기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ko/r1/tutorials/keras/basic_regression.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />깃허브(GitHub) 소스 보기</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YYwLLNVaaJU9",
        "colab_type": "text"
      },
      "source": [
        "Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도\n",
        "불구하고 [공식 영문 문서](https://www.tensorflow.org/?hl=en)의 내용과 일치하지 않을 수 있습니다.\n",
        "이 번역에 개선할 부분이 있다면\n",
        "[tensorflow/docs](https://github.com/tensorflow/docs) 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다.\n",
        "문서 번역이나 리뷰에 참여하려면\n",
        "[docs-ko@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ko)로\n",
        "메일을 보내주시기 바랍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AHp3M9ZmrIxj"
      },
      "source": [
        "*회귀*(regression)는 가격이나 확률 같이 연속된 출력 값을 예측하는 것이 목적입니다. 이와는 달리 *분류*(classification)는 여러개의 클래스 중 하나의 클래스를 선택하는 것이 목적입니다(예를 들어, 사진에 사과 또는 오렌지가 포함되어 있을 때 어떤 과일인지 인식하는 것).\n",
        "\n",
        "이 노트북은 [Auto MPG](https://archive.ics.uci.edu/ml/datasets/auto+mpg) 데이터셋을 사용하여 1970년대 후반과 1980년대 초반의 자동차 연비를 예측하는 모델을 만듭니다. 이 기간에 출시된 자동차 정보를 모델에 제공하겠습니다. 이 정보에는 실린더 수, 배기량, 마력(horsepower), 공차 중량 같은 속성이 포함됩니다.\n",
        "\n",
        "이 예제는 `tf.keras` API를 사용합니다. 자세한 내용은 [케라스 가이드](https://www.tensorflow.org/r1/guide/keras)를 참고하세요."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "moB4tpEHxKB3",
        "colab": {}
      },
      "source": [
        "# 산점도 행렬을 그리기 위해 seaborn 패키지를 설치합니다\n",
        "!pip install seaborn"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "1rRo8oNqZ-Rj",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals, unicode_literals\n",
        "\n",
        "import pathlib\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "import pandas as pd\n",
        "import seaborn as sns\n",
        "\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "from tensorflow.keras import layers\n",
        "\n",
        "print(tf.__version__)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "F_72b0LCNbjx"
      },
      "source": [
        "## Auto MPG 데이터셋\n",
        "\n",
        "이 데이터셋은 [UCI 머신 러닝 저장소](https://archive.ics.uci.edu/ml/)에서 다운로드할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gFh9ne3FZ-On"
      },
      "source": [
        "### 데이터 구하기\n",
        "먼저 데이터셋을 다운로드합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "p9kxxgzvzlyz",
        "colab": {}
      },
      "source": [
        "dataset_path = keras.utils.get_file(\"auto-mpg.data\", \"http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data\")\n",
        "dataset_path"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "nslsRLh7Zss4"
      },
      "source": [
        "판다스를 사용하여 데이터를 읽습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "CiX2FI4gZtTt",
        "colab": {}
      },
      "source": [
        "column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',\n",
        "                'Acceleration', 'Model Year', 'Origin']\n",
        "raw_dataset = pd.read_csv(dataset_path, names=column_names,\n",
        "                      na_values = \"?\", comment='\\t',\n",
        "                      sep=\" \", skipinitialspace=True)\n",
        "\n",
        "dataset = raw_dataset.copy()\n",
        "dataset.tail()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3MWuJTKEDM-f"
      },
      "source": [
        "### 데이터 정제하기\n",
        "\n",
        "이 데이터셋은 일부 데이터가 누락되어 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "JEJHhN65a2VV",
        "colab": {}
      },
      "source": [
        "dataset.isna().sum()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9UPN0KBHa_WI"
      },
      "source": [
        "문제를 간단하게 만들기 위해서 누락된 행을 삭제하겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "4ZUDosChC1UN",
        "colab": {}
      },
      "source": [
        "dataset = dataset.dropna()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8XKitwaH4v8h"
      },
      "source": [
        "`\"Origin\"` 열은 수치형이 아니고 범주형이므로 원-핫 인코딩(one-hot encoding)으로 변환하겠습니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gWNTD2QjBWFJ",
        "colab": {}
      },
      "source": [
        "origin = dataset.pop('Origin')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ulXz4J7PAUzk",
        "colab": {}
      },
      "source": [
        "dataset['USA'] = (origin == 1)*1.0\n",
        "dataset['Europe'] = (origin == 2)*1.0\n",
        "dataset['Japan'] = (origin == 3)*1.0\n",
        "dataset.tail()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Cuym4yvk76vU"
      },
      "source": [
        "### 데이터셋을 훈련 세트와 테스트 세트로 분할하기\n",
        "\n",
        "이제 데이터를 훈련 세트와 테스트 세트로 분할합니다.\n",
        "\n",
        "테스트 세트는 모델을 최종적으로 평가할 때 사용합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "qn-IGhUE7_1H",
        "colab": {}
      },
      "source": [
        "train_dataset = dataset.sample(frac=0.8,random_state=0)\n",
        "test_dataset = dataset.drop(train_dataset.index)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "J4ubs136WLNp"
      },
      "source": [
        "### 데이터 조사하기\n",
        "\n",
        "훈련 세트에서 몇 개의 열을 선택해 산점도 행렬을 만들어 살펴 보겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "oRKO_x8gWKv-",
        "colab": {}
      },
      "source": [
        "sns.pairplot(train_dataset[[\"MPG\", \"Cylinders\", \"Displacement\", \"Weight\"]], diag_kind=\"kde\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gavKO_6DWRMP"
      },
      "source": [
        "전반적인 통계도 확인해 보죠:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "yi2FzC3T21jR",
        "colab": {}
      },
      "source": [
        "train_stats = train_dataset.describe()\n",
        "train_stats.pop(\"MPG\")\n",
        "train_stats = train_stats.transpose()\n",
        "train_stats"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Db7Auq1yXUvh"
      },
      "source": [
        "### 특성과 레이블 분리하기\n",
        "\n",
        "특성에서 타깃 값 또는 \"레이블\"을 분리합니다. 이 레이블을 예측하기 위해 모델을 훈련시킬 것입니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "t2sluJdCW7jN",
        "colab": {}
      },
      "source": [
        "train_labels = train_dataset.pop('MPG')\n",
        "test_labels = test_dataset.pop('MPG')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mRklxK5s388r"
      },
      "source": [
        "### 데이터 정규화\n",
        "\n",
        "위 `train_stats` 통계를 다시 살펴보고 각 특성의 범위가 얼마나 다른지 확인해 보죠."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-ywmerQ6dSox"
      },
      "source": [
        "특성의 스케일과 범위가 다르면 정규화(normalization)하는 것이 권장됩니다. 특성을 정규화하지 않아도 모델이 *수렴할 수 있지만*, 훈련시키기 어렵고 입력 단위에 의존적인 모델이 만들어집니다.\n",
        "\n",
        "노트: 의도적으로 훈련 세트만 사용하여 통계치를 생성했습니다. 이 통계는 테스트 세트를 정규화할 때에도 사용됩니다. 이는 테스트 세트를 모델이 훈련에 사용했던 것과 동일한 분포로 투영하기 위해서입니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "JlC5ooJrgjQF",
        "colab": {}
      },
      "source": [
        "def norm(x):\n",
        "  return (x - train_stats['mean']) / train_stats['std']\n",
        "normed_train_data = norm(train_dataset)\n",
        "normed_test_data = norm(test_dataset)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "BuiClDk45eS4"
      },
      "source": [
        "정규화된 데이터를 사용하여 모델을 훈련합니다.\n",
        "\n",
        "주의: 여기에서 입력 데이터를 정규화하기 위해 사용한 통계치(평균과 표준편차)는 원-핫 인코딩과 마찬가지로 모델에 주입되는 모든 데이터에 적용되어야 합니다. 여기에는 테스트 세트는 물론 모델이 실전에 투입되어 얻은 라이브 데이터도 포함됩니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SmjdzxKzEu1-"
      },
      "source": [
        "## 모델"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "6SWtkIjhrZwa"
      },
      "source": [
        "### 모델 만들기\n",
        "\n",
        "모델을 구성해 보죠. 여기에서는 두 개의 완전 연결(densely connected) 은닉층으로 `Sequential` 모델을 만들겠습니다. 출력 층은 하나의 연속적인 값을 반환합니다. 나중에 두 번째 모델을 만들기 쉽도록 `build_model` 함수로 모델 구성 단계를 감싸겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "c26juK7ZG8j-",
        "colab": {}
      },
      "source": [
        "def build_model():\n",
        "  model = keras.Sequential([\n",
        "    layers.Dense(64, activation=tf.nn.relu, input_shape=[9]),\n",
        "    layers.Dense(64, activation=tf.nn.relu),\n",
        "    layers.Dense(1)\n",
        "  ])\n",
        "\n",
        "  optimizer = tf.keras.optimizers.RMSprop(0.001)\n",
        "\n",
        "  model.compile(loss='mean_squared_error',\n",
        "                optimizer=optimizer,\n",
        "                metrics=['mean_absolute_error', 'mean_squared_error'])\n",
        "  return model"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "cGbPb-PHGbhs",
        "colab": {}
      },
      "source": [
        "model = build_model()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Sj49Og4YGULr"
      },
      "source": [
        "### 모델 확인\n",
        "\n",
        "`.summary` 메서드를 사용해 모델에 대한 간단한 정보를 출력합니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ReAD0n6MsFK-",
        "colab": {}
      },
      "source": [
        "model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Vt6W50qGsJAL"
      },
      "source": [
        "모델을 한번 실행해 보죠. 훈련 세트에서 `10` 샘플을 하나의 배치로 만들어 `model.predict` 메서드를 호출해 보겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "-d-gBaVtGTSC",
        "colab": {}
      },
      "source": [
        "example_batch = normed_train_data[:10]\n",
        "example_result = model.predict(example_batch)\n",
        "example_result"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QlM8KrSOsaYo"
      },
      "source": [
        "제대로 작동하는 것 같네요. 결괏값의 크기와 타입이 기대했던 대로입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0-qWCsh6DlyH"
      },
      "source": [
        "### 모델 훈련\n",
        "\n",
        "이 모델을 1,000번의 에포크(epoch) 동안 훈련합니다. 훈련 정확도와 검증 정확도는 `history` 객체에 기록됩니다."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sD7qHCmNIOY0",
        "colab": {}
      },
      "source": [
        "# 에포크가 끝날 때마다 점(.)을 출력해 훈련 진행 과정을 표시합니다\n",
        "class PrintDot(keras.callbacks.Callback):\n",
        "  def on_epoch_end(self, epoch, logs):\n",
        "    if epoch % 100 == 0: print('')\n",
        "    print('.', end='')\n",
        "\n",
        "EPOCHS = 1000\n",
        "\n",
        "history = model.fit(\n",
        "  normed_train_data, train_labels,\n",
        "  epochs=EPOCHS, validation_split = 0.2, verbose=0,\n",
        "  callbacks=[PrintDot()])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "tQm3pc0FYPQB"
      },
      "source": [
        "`history` 객체에 저장된 통계치를 사용해 모델의 훈련 과정을 시각화해 보죠."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "4Xj91b-dymEy",
        "colab": {}
      },
      "source": [
        "hist = pd.DataFrame(history.history)\n",
        "hist['epoch'] = history.epoch\n",
        "hist.tail()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "B6XriGbVPh2t",
        "colab": {}
      },
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "def plot_history(history):\n",
        "  hist = pd.DataFrame(history.history)\n",
        "  hist['epoch'] = history.epoch\n",
        "\n",
        "  plt.figure(figsize=(8,12))\n",
        "\n",
        "  plt.subplot(2,1,1)\n",
        "  plt.xlabel('Epoch')\n",
        "  plt.ylabel('Mean Abs Error [MPG]')\n",
        "  plt.plot(hist['epoch'], hist['mean_absolute_error'],\n",
        "           label='Train Error')\n",
        "  plt.plot(hist['epoch'], hist['val_mean_absolute_error'],\n",
        "           label = 'Val Error')\n",
        "  plt.ylim([0,5])\n",
        "  plt.legend()\n",
        "\n",
        "  plt.subplot(2,1,2)\n",
        "  plt.xlabel('Epoch')\n",
        "  plt.ylabel('Mean Square Error [$MPG^2$]')\n",
        "  plt.plot(hist['epoch'], hist['mean_squared_error'],\n",
        "           label='Train Error')\n",
        "  plt.plot(hist['epoch'], hist['val_mean_squared_error'],\n",
        "           label = 'Val Error')\n",
        "  plt.ylim([0,20])\n",
        "  plt.legend()\n",
        "  plt.show()\n",
        "\n",
        "plot_history(history)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AqsuANc11FYv"
      },
      "source": [
        "이 그래프를 보면 수 백번 에포크를 진행한 이후에는 모델이 거의 향상되지 않는 것 같습니다. `model.fit` 메서드를 수정하여 검증 점수가 향상되지 않으면 자동으로 훈련을 멈추도록 만들어 보죠. 에포크마다 훈련 상태를 점검하기 위해 *EarlyStopping 콜백(callback)*을 사용하겠습니다. 지정된 에포크 횟수 동안 성능 향상이 없으면 자동으로 훈련이 멈춥니다.\n",
        "\n",
        "이 콜백에 대해 더 자세한 내용은 [여기](https://www.tensorflow.org/versions/master/api_docs/python/tf/keras/callbacks/EarlyStopping)를 참고하세요."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "fdMZuhUgzMZ4",
        "colab": {}
      },
      "source": [
        "model = build_model()\n",
        "\n",
        "# patience 매개변수는 성능 향상을 체크할 에포크 횟수입니다\n",
        "early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)\n",
        "\n",
        "history = model.fit(normed_train_data, train_labels, epochs=EPOCHS,\n",
        "                    validation_split = 0.2, verbose=0, callbacks=[early_stop, PrintDot()])\n",
        "\n",
        "plot_history(history)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "3St8-DmrX8P4"
      },
      "source": [
        "이 그래프를 보면 검증 세트의 평균 오차가 약 +/- 2 MPG입니다. 좋은 결과인가요? 이에 대한 평가는 여러분에게 맡기겠습니다.\n",
        "\n",
        "모델을 훈련할 때 사용하지 않았던 **테스트 세트**에서 모델의 성능을 확인해 보죠. 이를 통해 모델이 실전에 투입되었을 때 모델의 성능을 짐작할 수 있습니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jl_yNr5n1kms",
        "colab": {}
      },
      "source": [
        "loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=2)\n",
        "\n",
        "print(\"테스트 세트의 평균 절대 오차: {:5.2f} MPG\".format(mae))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ft603OzXuEZC"
      },
      "source": [
        "## 예측\n",
        "\n",
        "마지막으로 테스트 세트에 있는 샘플을 사용해 MPG 값을 예측해 보겠습니다:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Xe7RXH3N3CWU",
        "colab": {}
      },
      "source": [
        "test_predictions = model.predict(normed_test_data).flatten()\n",
        "\n",
        "plt.scatter(test_labels, test_predictions)\n",
        "plt.xlabel('True Values [MPG]')\n",
        "plt.ylabel('Predictions [MPG]')\n",
        "plt.axis('equal')\n",
        "plt.axis('square')\n",
        "plt.xlim([0,plt.xlim()[1]])\n",
        "plt.ylim([0,plt.ylim()[1]])\n",
        "_ = plt.plot([-100, 100], [-100, 100])\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mU1jBsRLaCeY",
        "colab_type": "text"
      },
      "source": [
        "모델이 꽤 잘 예측한 것 같습니다. 오차의 분포를 살펴 보죠."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "f-OHX4DiXd8x",
        "colab": {}
      },
      "source": [
        "error = test_predictions - test_labels\n",
        "plt.hist(error, bins = 25)\n",
        "plt.xlabel(\"Prediction Error [MPG]\")\n",
        "_ = plt.ylabel(\"Count\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3PkzkjFkaCed",
        "colab_type": "text"
      },
      "source": [
        "가우시안 분포가 아니지만 아마도 훈련 샘플의 수가 매우 작기 때문일 것입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vgGQuV-yqYZH"
      },
      "source": [
        "## 결론\n",
        "\n",
        "이 노트북은 회귀 문제를 위한 기법을 소개합니다.\n",
        "\n",
        "* 평균 제곱 오차(MSE)는 회귀 문제에서 자주 사용하는 손실 함수입니다(분류 문제에서 사용하는 손실 함수와 다릅니다).\n",
        "* 비슷하게 회귀에서 사용되는 평가 지표도 분류와 다릅니다. 많이 사용하는 회귀 지표는 평균 절댓값 오차(MAE)입니다.\n",
        "* 수치 입력 데이터의 특성이 여러 가지 범위를 가질 때 동일한 범위가 되도록 각 특성의 스케일을 독립적으로 조정해야 합니다.\n",
        "* 훈련 데이터가 많지 않다면 과대적합을 피하기 위해 은닉층의 개수가 적은 소규모 네트워크를 선택하는 방법이 좋습니다.\n",
        "* 조기 종료(Early stopping)은 과대적합을 방지하기 위한 좋은 방법입니다."
      ]
    }
  ]
}